﻿using System;
using System.Collections.Generic;

namespace AIC_Notification
{
    public class DayCount 
    {
        public struct Holiday
        {
            public DateTime Date;
            public int Span;

            public Holiday(DateTime date, int span)
            {
                this.Date = date;
                this.Span = span;
            }
        }

        public IList<Holiday> restdays;
        public IList<Holiday> specialWorkingDays;

        public DayCount()
        {
/*
            restdays = new List<Holiday>();
            restdays.Add(new Holiday(new DateTime(2017, 4, 3), 2));     //清明
            restdays.Add(new Holiday(new DateTime(2017, 5, 1), 1));     //劳动节
            restdays.Add(new Holiday(new DateTime(2017, 1, 2), 1));     //元旦
            restdays.Add(new Holiday(new DateTime(2017, 5, 29), 2));    //端午
            restdays.Add(new Holiday(new DateTime(2017, 1, 27), 1));    //春节
            restdays.Add(new Holiday(new DateTime(2017, 1, 30), 4));    //2春节
            restdays.Add(new Holiday(new DateTime(2017, 10, 2), 5));    //国庆中秋

            specialWorkingDays = new List<Holiday>();
            specialWorkingDays.Add(new Holiday(new DateTime(2017, 4, 1), 1));   //清明
            specialWorkingDays.Add(new Holiday(new DateTime(2017, 1, 2), 1));   //元旦
            specialWorkingDays.Add(new Holiday(new DateTime(2017, 5, 27), 1));  //端午
            specialWorkingDays.Add(new Holiday(new DateTime(2017, 1, 22), 1));  //春节
            specialWorkingDays.Add(new Holiday(new DateTime(2017, 2, 4), 1));   //2春节
            specialWorkingDays.Add(new Holiday(new DateTime(2017, 9, 30), 1));  //国庆中秋
*/
        }

        public TimeSpan WorkingDaysBetween(DateTime firstDay, DateTime lastDay)
        {
            DateTime firstDate = firstDay.Date;
            DateTime lastDate = lastDay.Date;
            if (firstDate > lastDate) return new TimeSpan(0);
            TimeSpan span = lastDate - firstDate;
            int workingDays = 0;
            int fullWeekCnt = (span.Days + 1) / 7;
            int firstweek = Convert.ToInt32(firstDate.DayOfWeek);
            firstweek = (firstweek != 0) ? firstweek : 7;
            int lastweek = Convert.ToInt32(lastDate.DayOfWeek);
            lastweek = (lastweek != 0) ? lastweek : 7;
            bool isFirstDayWorkingDay = false, isLastDayWorkingDay = false;
            if (firstweek < 6)
            {
                isFirstDayWorkingDay = true;
            }
            if (lastweek < 6)
            {
                isLastDayWorkingDay = true;
            }
            if (span.Days + 1 > fullWeekCnt * 7)
            {

                if (lastweek >= firstweek) fullWeekCnt--;
                if (firstweek < 6) workingDays += 6 - firstweek;
                if (lastweek < 6) workingDays += lastweek;
                if (lastweek >= 6) workingDays += 5;
            }
            workingDays += 5 * fullWeekCnt;

            foreach (Holiday restday in restdays)
            {
                DateTime start = restday.Date;
                DateTime end = restday.Date.AddDays(restday.Span - 1);
                if (start <= firstDate && firstDate <= end)
                {
                    isFirstDayWorkingDay = false;
                }
                if (start <= lastDate && lastDate <= end)
                {
                    isLastDayWorkingDay = false;
                }
                if (firstDate <= end && start <= lastDate)
                {
                    DateTime tmp = start;
                    while (!tmp.Equals(end))
                    {
                        if (firstDate <= tmp && tmp <= lastDate) workingDays--;
                        tmp = tmp.AddDays(1);
                    }
                    if (firstDate <= end && end <= lastDate) workingDays--;
                }
            }
            foreach (Holiday specialWorkingDay in specialWorkingDays)
            {
                DateTime start = specialWorkingDay.Date;
                DateTime end = specialWorkingDay.Date.AddDays(specialWorkingDay.Span - 1);
                if (firstDate <= end && start <= lastDate)
                {
                    if (start <= firstDate && firstDate <= end)
                    {
                        isFirstDayWorkingDay = true;
                    }
                    if (start <= lastDate && lastDate <= end)
                    {
                        isLastDayWorkingDay = true;
                    }
                    DateTime tmp = start;
                    while (!tmp.Equals(end))
                    {
                        if (firstDate <= tmp && tmp <= lastDate) workingDays++;
                        tmp = tmp.AddDays(1);
                    }
                    if (firstDate <= end && end <= lastDate) workingDays++;
                }
            }
            TimeSpan workingDaysSpan = new TimeSpan(workingDays, 0, 0, 0);
            if (isFirstDayWorkingDay)
            {
                workingDaysSpan = workingDaysSpan - (firstDay - firstDate);
            }
            if (isLastDayWorkingDay)
            {
                workingDaysSpan = workingDaysSpan - (lastDate.AddDays(1) - lastDay);
            }
            return workingDaysSpan;
        }
    }
}
